package org.cloud.common.util;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.EncodeHintType;
import com.google.zxing.FormatException;
import com.google.zxing.LuminanceSource;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
 * 二维码工具类
 * 
 * @author wangyuan
 * @since 2019年2月11日
 */
public class QRCodeUtils {
    
    private static final String IMAGE_DEFAULT_FORMAT = "jpeg";
    private static final int CODE_DEFAULT_SIZE = 260;

    /**
     * 生成二维码
     * 
     * @param content 二维码内容
     * @param codeSize 二维码尺寸
     * @param imageFormatName 生成的图片后缀名
     * @return
     * @throws IOException
     * @throws WriterException
     */
    public static ByteArrayOutputStream createQRCode(String content, int codeSize, String imageFormatName) throws IOException, WriterException {
        //二维码纠错级别MAP
        HashMap<EncodeHintType, ErrorCorrectionLevel> hintMap = new HashMap<>();
        hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
        
        //创建比特矩阵(位矩阵)的QR码编码的字符串
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, codeSize, codeSize, hintMap);
        
        //获取有意义的像素点位置
        int[] topLeft = bitMatrix.getTopLeftOnBit();
        int[] bottomRight = bitMatrix.getBottomRightOnBit();
        
        //计算二维码实际长和宽
        int imageWidth = bottomRight[0] - topLeft[0];
        int imageHeight = bottomRight[1] - topLeft[1];
        
        //使BufferedImage勾画二维码
        BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = image.createGraphics();
        
        //设置图像底色为白色
        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, imageWidth, imageHeight);
        
        //使用比特矩阵画出图像
        graphics.setColor(Color.BLACK);
        for(int i = 0;i < imageWidth;i++){
            for(int j = 0;j < imageHeight;j++){
                if(bitMatrix.get(i + topLeft[0], j + topLeft[1])){
                    graphics.fillRect(i, j, 1, 1);
                }
            }
        }
        
        //保存图像
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        ImageIO.write(image, imageFormatName, output);
        
        return output;
    }
    
    /**
     * 生成二维码，按给定的文件路径保存二维码
     * 
     * @param filePath 二维码文件路径
     * @param content
     * @param codeSize
     * @param imageFormatName
     * @throws IOException
     * @throws WriterException
     */
    public static void createQRCode(String filePath, String content, int codeSize, String imageFormatName) throws IOException, WriterException {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(filePath);
            ByteArrayOutputStream output = createQRCode(content, codeSize, imageFormatName);
            out.write(output.toByteArray());
        } catch (IOException e) {
            throw e;
        } catch(WriterException e) {
            throw e;
        } finally {
            StreamUtils.close(out);
        }
    }
    
    /**
     * 生成二维码，生成的二维码后缀为jpeg
     * 
     * @param content
     * @param codeSize
     * @return
     * @throws IOException
     * @throws WriterException
     */
    public static ByteArrayOutputStream createQRCode(String content, int codeSize) throws IOException, WriterException {
        return createQRCode(content, codeSize, IMAGE_DEFAULT_FORMAT);
    }
    
    /**
     * 生成二维码，生成的二维码后缀默认为jpeg，并且是默认大小
     * @param content
     * @return
     * @throws IOException
     * @throws WriterException
     */
    public static ByteArrayOutputStream createQRCode(String content) throws IOException, WriterException {
        return createQRCode(content, CODE_DEFAULT_SIZE, IMAGE_DEFAULT_FORMAT);
    }
    
    /**
     * 读取二维码
     * @param inputStream
     * @return
     * @throws IOException
     * @throws NotFoundException
     * @throws ChecksumException
     * @throws FormatException
     */
    public static String readQRCode(InputStream inputStream) throws IOException, NotFoundException, ChecksumException, FormatException {
        //从输入流中获取字符串信息
        BufferedImage image = ImageIO.read(inputStream);
        //将图像转换为二进制位图源
        LuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        QRCodeReader reader = new QRCodeReader();
        Result result = reader.decode(bitmap);
        if(result == null){
            return null;
        } else {
            return result.getText();
        }
    }
}
